package main

import (
	"fmt"
)

func main()  {
	aa := `
goroutine：
并发函数，与其他代码一起运行。可以在函数之前添加go关键字来触发。
示例：
func main() {
   go sayHello()
   //继续执行自己的逻辑
}
func sayHello () {
   fmt.Println("hello")
}

基于匿名函数的goroutine示例：
go func() {
   fmt.Println("hello")
}()    //在go关键字后面调用匿名函数来使用
//继续执行自己的逻辑

将函数赋给一个变量，并将其命名为匿名函数
sayHello := func() {
   fmt.Println("hello")
}
go sayHello()
//继续执行自己的逻辑

goroutine 不是OS线程，不是绿色线程(由语言运行时管理的线程)，是协程，是一种更高级别的抽象
协程：
一种非抢占式的简单并发子goroutine(函数，闭包或方法),他们不能被中断，协程有多个点，允许暂停或重新进入

go语言的独特之处在于他们与狗语言的运行时的深度集成
协程和goroutine都是隐式并发结构，但并发并不是协程的属性

测算在goroutine创建之前后之后分配的内存数量
goroutine不被GC的事实与运行时的自省能力结合

memConsumed := func() uint64 {
   runtime.GC()
   var s runtime.MemStats
   runtime.ReadMemStats(&s)
   return s.Sys
}

var c <-chan interface{}
var wg sync.WaitGroup
noop := func() { wg.Done(); <-c}   //不会退出的goroutine，直到进程结束，用于测算

const numGrouptines = 1e4  //定义要创建goroutine的数量，使用大数定律，接近一个goroutine的大小
wg.Add(numGoroutines)
before := memConsumed()    //测算在创建goroutine之前消耗的内存总量
for i := numGoroutines; i > 0; i-- {
   go noop()
}
wg.Wait()
agter := memConsumed() //测算在创建goroutine之后消耗的总量
fmt.Printf("%.3fkb",float64(after-before)/numGoroutines/1000)

创建两个goroutine并在他们之间发送一条消息
func BenchmarkContextSwitch(b *testint.B) {
   var wg sync.WaitGroup
   begin := make(chan struct{})
   c := make(chan struct{})

   var token struct{}
   sender := func() {
      defer wg.Done()
      <-begin    //等待被告知开始执行，对上下文切换度量时不考虑设置和启动每个goroutine成本
      for i := 0; i < b.N;i++ {
         c <- token //将消息发送到接收器goroutine，做发出信号时候记录时间用
      }
   }
   reciever := func() {
      defer wg.Done()
      <-begin    //等待被告知开始执行，对上下文切换度量时不考虑设置和启动每个goroutine成本
      for i := 0;i < b.N;i++ {
         <-c    //收到消息
      }
   }
   wg.Add(2)
   go sender()
   go receiver()
   b.StartTimer() //开始计时
   close(begin)   告诉俩个goroutine开始运行
   wg.wait()
}

使用一个CPU进行基准测试
go test -bench=. -cpu=1 程序文件路径及名称





`

fmt.Println(aa)



}


